package cn.joeg.app;

import cn.joeg.app.dto.OptInfo;
import cn.joeg.app.fun.VoidExecutor;
import com.ecfront.dew.common.JsonHelper;
import com.ecfront.dew.common.TimerHelper;
import com.ecfront.dew.core.cluster.Cluster;
import com.ecfront.dew.core.cluster.ClusterCache;
import com.ecfront.dew.core.cluster.ClusterDist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 游戏核心模块
 *
 * @author Joeg
 * @email 840459673@qq.com
 * @date 2018/4/10
 */
@Component
public class GCore {


    @Autowired
    @Qualifier("gCoreConfig")
    private GCoreConfig gCoreConfig;

    @Autowired
    private ApplicationContext _applicationContext;

    public static Cluster cluster = new Cluster();

    public static ApplicationContext applicationContext;


    @PostConstruct
    public void init() {
        GCore.applicationContext = _applicationContext;
        if (GCore.applicationContext.containsBean(gCoreConfig.getCluster().getCache() + "ClusterCache")) {
            GCore.cluster.cache = (ClusterCache) GCore.applicationContext.getBean(gCoreConfig.getCluster().getCache() + "ClusterCache");
        }
        if (GCore.applicationContext.containsBean(gCoreConfig.getCluster().getDist() + "ClusterDist")) {
            GCore.cluster.dist = (ClusterDist) GCore.applicationContext.getBean(gCoreConfig.getCluster().getDist() + "ClusterDist");
        }

    }


    public static class Constant {
        // token存储key
        public static final String TOKEN_INFO_FLAG = "gcore:auth:token:info:";
        // Token Id 关联 key : dew:auth:token:id:rel:<code> value : <token Id>
        public static final String TOKEN_ID_REL_FLAG = "gcore:auth:token:id:rel:";
        // 前端传入的token标识
        public static final String TOKEN_VIEW_FLAG = "__gcore_token__";

    }


    /**
     * 组件基础信息
     */
    public static class Info {
        // 应用名称
        public static String name;
        // 应用主机IP
        public static String ip;
        // 应用主机名
        public static String host;
        // 应用实例，各组件唯一
        public static String instance = GCore.Util.createUUID();

        static {
            try {
                name = GCore.applicationContext.getId();
                ip = InetAddress.getLocalHost().getHostAddress();
                host = InetAddress.getLocalHost().getHostName();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }

    }


    /**
     * 获取请求上下文信息
     *
     * @return 请求上下文信息
     */
    public static GCoreContext context() {
        return GCoreContext.getContext();
    }


    /**
     * 定时器支持（带请求上下文绑定）
     */
    public static class Timer {

        private static final Logger logger = LoggerFactory.getLogger(Timer.class);

        public static void periodic(long initialDelaySec, long periodSec, VoidExecutor fun) {
            GCoreContext context = GCore.context();
            TimerHelper.periodic(initialDelaySec, periodSec, () -> {
                GCoreContext.setContext(context);
                try {
                    fun.exec();
                } catch (Exception e) {
                    logger.error("[Timer] Execute error", e);
                }
            });
        }

        public static void periodic(long periodSec, VoidExecutor fun) {
            periodic(0, periodSec, fun);
        }

        public static void timer(long delaySec, VoidExecutor fun) {
            GCoreContext context = GCore.context();
            TimerHelper.timer(delaySec, () -> {
                GCoreContext.setContext(context);
                try {
                    fun.exec();
                } catch (Exception e) {
                    logger.error("[Timer] Execute error", e);
                }
            });
        }

    }


    /**
     * 常用工具
     */
    public static class Util {

        private static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
                "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
                "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
                "W", "X", "Y", "Z"};

        public static String createUUID() {
            return UUID.randomUUID().toString().replace("-", "");
        }

        public static String createShortUUID() {
            StringBuilder shortBuffer = new StringBuilder();
            String uuid = createUUID();
            for (int i = 0; i < 8; i++) {
                String str = uuid.substring(i * 4, i * 4 + 4);
                int x = Integer.parseInt(str, 16);
                shortBuffer.append(chars[x % 0x3E]);
            }
            return shortBuffer.toString();
        }

        public static String getRealIP(HttpServletRequest request) {
            Map<String, String> requestHeader = new HashMap<>();
            Enumeration<String> header = request.getHeaderNames();
            while (header.hasMoreElements()) {
                String key = header.nextElement();
                requestHeader.put(key.toLowerCase(), request.getHeader(key));
            }
            return getRealIP(requestHeader, request.getRemoteAddr());
        }

        public static String getRealIP(Map<String, String> requestHeader, String remoteAddr) {
            if (requestHeader.containsKey("x-forwarded-for") && requestHeader.get("x-forwarded-for") != null && !requestHeader.get("x-forwarded-for").isEmpty()) {
                return requestHeader.get("x-forwarded-for");
            }
            if (requestHeader.containsKey("wl-proxy-client-ip") && requestHeader.get("wl-proxy-client-ip") != null && !requestHeader.get("wl-proxy-client-ip").isEmpty()) {
                return requestHeader.get("wl-proxy-client-ip");
            }
            if (requestHeader.containsKey("x-forwarded-host") && requestHeader.get("x-forwarded-host") != null && !requestHeader.get("x-forwarded-host").isEmpty()) {
                return requestHeader.get("x-forwarded-host");
            }
            return remoteAddr;
        }

        private static ExecutorService executorService = Executors.newCachedThreadPool();

        public static void newThread(Runnable fun) {
            executorService.execute(fun);
        }

        public static class RunnableWithContext implements Runnable {

            private VoidExecutor fun;
            private GCoreContext context;

            public RunnableWithContext(VoidExecutor fun) {
                this.fun = fun;
                this.context = GCoreContext.getContext();
            }

            @Override
            public void run() {
                GCoreContext.setContext(context);
                fun.exec();
            }
        }

        public static Optional<OptInfo> getOptInfoByAccCode(String accountCode) {
            String token = GCore.cluster.cache.get(GCore.Constant.TOKEN_ID_REL_FLAG + accountCode);
            if (token != null && !token.isEmpty()) {
                return Optional.of(JsonHelper.toObject(GCore.cluster.cache.get(GCore.Constant.TOKEN_INFO_FLAG + token), OptInfo.class));
            } else {
                return Optional.empty();
            }
        }

    }


}
